package com.ews.onlineexchange.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.transaction.Transactional;

import org.apache.commons.io.FileUtils;

import com.ews.onlineexchange.model.Attachment;
import com.ews.onlineexchange.model.Bulletin;
import com.ews.onlineexchange.model.Image;
import com.ews.onlineexchange.model.OfferPrice;
import com.ews.onlineexchange.model.ServiceSupplier;
import com.ews.onlineexchange.model.Trade;
import com.ews.onlineexchange.model.TradeStatus;
import com.ews.onlineexchange.model.bulletinRequirement.Requirement;
import com.ews.onlineexchange.util.Config;

@Stateless
public class TradeService implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String FILE_SEPARATOR = "/";
	
	@Inject
	EntityManager				entityManager;

	@Inject
	Config						config;
	
	private final String GET_TRADES_BY_BULLETIN = ""
			+ " from Trade trade"
			+ " WHERE trade.bulletin.id = :bulletinId"
			+ "";
	@SuppressWarnings( "unchecked" )
	public List<Trade> getTradesByBulletinId(String bulletinId){
		
		return entityManager.createQuery(GET_TRADES_BY_BULLETIN).setParameter("bulletinId", bulletinId).getResultList();
		
	}
	
	@Transactional
	public void merge(Trade trade) {
		entityManager.merge(trade);
	}
	
	public Trade getTradeById(String tradeId) {
		try {
			Trade trade = entityManager.find(Trade.class, tradeId);
			return trade;
		} catch (Exception e) {
			return null;
		}
	}
	
	@Transactional
	public void updateOfferPrice(Trade trade,BigDecimal price) {
		trade.setOffer(price);
		trade.setOfferCount(trade.getOfferCount() + 1);
		entityManager.merge(trade);
		OfferPrice offer = new OfferPrice();
		offer.setNewMaxOffer(price);
		offer.setTrade(trade);
		entityManager.merge(offer);
	}
	
	private final static String GET_OFFERPRICE_BY_TRADE_ID_HQL = ""
			+ "	SELECT offerPrice						"
			+ "	FROM OfferPrice offerPrice				"
			+ "	WHERE offerPrice.delFlag = '0'			"
			+ "	AND	 offerPrice.trade.id = :tradeId		";
	
	@SuppressWarnings( "unchecked" )
	public List<OfferPrice> getOfferPriceListByTradeId(String tradeId){
		List<OfferPrice> list = entityManager.createQuery(GET_OFFERPRICE_BY_TRADE_ID_HQL).setParameter("tradeId", tradeId).getResultList();
		return list;
	}

	private static final String QUERY_CONFILCTING_TRADES_EQL = ""
			+ "		SELECT			t "
			+ "		FROM			Trade t "
			+ "		WHERE		(	t.bulletin.id = :rootConflictingBulletinId OR t.bulletin.conflictingBulletin.id = :rootConflictingBulletinId		) "
			+ "		AND				t.supplier.id = :supplierId"
			+ " 	AND				t.bulletin.tradeStatus IN (	:tradeStatuses ) ";
	@Transactional
	public void invalidateConflictingTrades( Bulletin bulletin ) {
		String rootId;
		if ( bulletin.getRootConflictingBulletin() == null ) {
			rootId = bulletin.getId();
		} else {
			rootId = bulletin.getRootConflictingBulletin().getId();
		}
		
		Query query = entityManager.createQuery( QUERY_CONFILCTING_TRADES_EQL );
		query.setParameter( "rootConflictingBulletinId", rootId );
		query.setParameter( "supplierId", bulletin.getSuccessTrade().getSupplier().getId() );
		
		query.setParameter( "tradeStatuses",
				Arrays.asList( new TradeStatus[] { TradeStatus.Opened, TradeStatus.Waiting, TradeStatus.Paused } ) );
		List<Trade> conflictingTrades = query.getResultList();
		for ( Trade trade : conflictingTrades ) {
			trade.setHasVerify(false);
			trade.setVerifyTime(null);
			entityManager.merge( trade );
		}
	}
	
	private static final String QUERY_EXIST_DEALER_EQL = ""
			+ "		SELECT			b.successTrade "
			+ "		FROM			Bulletin b "
			+ "		WHERE		(	b.id = :rootConflictingBulletinId OR b.conflictingBulletin.id = :rootConflictingBulletinId		) "
			+ "		AND				b.tradeStatus = :agreedStatus ";
	public List<Trade> queryExistDealers( Bulletin bulletin ) {
		String rootId;
		if ( bulletin.getRootConflictingBulletin() == null ) {
			return new ArrayList<Trade>();
		} else {
			rootId = bulletin.getRootConflictingBulletin().getId();
		}
		
		Query query = entityManager.createQuery( QUERY_EXIST_DEALER_EQL );
		query.setParameter( "rootConflictingBulletinId", rootId );
		query.setParameter( "agreedStatus", TradeStatus.Agreed );
		return query.getResultList();
	}
	
	public File archive( String id ) {
		Trade trade = entityManager.find( Trade.class, id );
		
		InputStream input = null;		
		String rootDir = config.getProperty( "com.ews.onlineExchange.saveDir" ) + "archive" + FILE_SEPARATOR + trade.getBulletin().getId() + FILE_SEPARATOR + trade.getId();
		File tradeRootDir = new File( rootDir );
		try {
			
			if ( !tradeRootDir.exists() ) {
				FileUtils.forceMkdir( tradeRootDir );
			}
			
			File zipFile = File.createTempFile( trade.getBulletin().getProjectName().concat( "_" ).concat( trade.getSupplier().getCnname() ).concat( "报名材料" ), ".zip",
					tradeRootDir.getParentFile().getAbsoluteFile() );
			ZipOutputStream zipOut = new ZipOutputStream( new FileOutputStream( zipFile ) );
			
			FileUtils.forceMkdir( tradeRootDir );
			
			for ( Requirement _req : trade.getRequirements() ) {
				for ( Attachment _a : _req.getAttachments() ) {
					zipOut.putNextEntry( new ZipEntry( tradeRootDir.getName() + FILE_SEPARATOR + _req.getRequirementDefination().getRequiredName() + FILE_SEPARATOR + "附件" + FILE_SEPARATOR + _a.getFilename() ) );		
					input = new FileInputStream( _a.getFile() );
					int temp = 0;
					while ( (temp = input.read()) != -1 ) {
						zipOut.write( temp );
					}
					input.close();
				}
				
				for ( Image _a : _req.getImages() ) {
					zipOut.putNextEntry( new ZipEntry( tradeRootDir.getName() + FILE_SEPARATOR + _req.getRequirementDefination().getRequiredName() + FILE_SEPARATOR + "图像" + FILE_SEPARATOR + _a.getFilename() ) );	
					input = new FileInputStream( _a.getFile() );
					int temp = 0;
					while ( (temp = input.read()) != -1 ) {
						zipOut.write( temp );
					}
					input.close();
				}
			}

			zipOut.close();
			
			return zipFile;
		} catch ( IOException e ) {
			e.printStackTrace();
		} 
		
		throw new RuntimeException();
	}	
	@Inject
	TradeSeqNoGenerator tradeSeqNoGenerator;
	
	@Transactional
	public Trade generateTrade(Bulletin bulletin,ServiceSupplier supplier) {
		Trade trade = new Trade();
		trade.setSupplier(supplier);
		trade.setBulletin(bulletin);
		trade.setSerialNumber(tradeSeqNoGenerator.getNextSeqNo());
		entityManager.merge(trade);
		return trade;
	}
	
}
